home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / graphics / vlapak1.zip / MODINFO.ZIP / MODINFO.DOC < prev    next >
Text File  |  1993-04-16  |  38KB  |  926 lines

  1.  
  2.                MORE ABOUT MODS THAN YOU NEED TO KNOW
  3.  
  4.      Hello, fellow programmers!  This is Draeden hacking out this
  5. info file.  When I start working on my MOD player nearly a year ago,
  6. I really wanted SOME piece of information on MODs.  I could find NOTHING!
  7. So The Kabal and I had to figure the format of a mod out ourselves.
  8. Needless to say, my first try was a disaster.  It worked, but not very 
  9. well.  (Incidently, that code is available as 'MODPLAY.ZIP' on Phantasm, and
  10. possibly on a local FTP site.)  Since then, I've rewritten my MOD player 
  11. and now it actually plays The Finn's MODs correctly (made him happy.)  
  12. Anyway, this DOC is intended to help out all those people who want to write 
  13. a MOD player (and have the skills to actually do it.)  There is quite a bit 
  14. of assembly required. (Har, har. A pun.)
  15.  
  16.      So, far you've probably seen plenty of documentation on what
  17. the format of a .MOD is and what each little thingy in the .MOD format
  18. means.  Well, I'm going to repeat that same info, BUT it's going to
  19. be translated so that it's usable on the Sound Blaster AND I'm
  20. going to explain how to get that little card to make some noise.
  21.  
  22.      On the SoundBlaster there are two ways to playback digital
  23. samples. The first is to directly write the sample data to the
  24. card MANUALLY, via a method which I call polling.  A timer
  25. interrupt must be set up to go off FOR EACH BYTE PLAYED.
  26. (Usually around 12,000 times a second.)  This, of course, eats up
  27. a lot of processor time and causes the program that's playing (ie. a
  28. demo/game) to be VERY SLOW.  The advantage to this method is that you
  29. can do playback on a large variety of equipment (ie. PC speaker,
  30. Adlib, DAC converters , Covox, or whatever...)  See  the included file
  31. "POLLPLAY.ASM" for an example of how to do that type of playback.
  32. If you have a LPT DAC, see "DACPLAY.ASM"  I won't spend too long talking
  33. about it- it's pretty strait forward and simple.
  34.  
  35. ────────────────────────────────────────────────────────────────────────────
  36.  
  37. Here's a quick outline of what you have to do (for SB poll mode):
  38.  
  39.  1) Set up your interrupt (int 8, the timer)
  40.  2) Reset the DSP, Turn on the speaker
  41.  3) Turn the Timer interrupt on and program it
  42.  
  43.  4) ...Do your stuff... (sound is playing, now)
  44.  
  45.  5) Turn off the speaker
  46.  6) Shut off the timer interrupt
  47.  6) Restore the old interrupt
  48.  
  49. Your interrupt must do this:
  50.  
  51.  1) Get the next byte to be played
  52.  2) Play it
  53.     a) for the soundblaster send the command 10h, then the byte
  54.  3) Acknowledge the interrupt
  55.  
  56. And that's all there is to it!  See POLLPLAY.ASM for specifics.
  57. See DACPLAY.ASM for a more general setup.
  58.  
  59. ────────────────────────────────────────────────────────────────────────────
  60.  
  61.      The other (and much preferred) way is through the DMA.  This
  62. is the quickest way to do digital playback on the SoundBlaster. 
  63. The only drawback is that it is quite a bit more complicated
  64. than the polling method.  You have to set up the DSP then set up
  65. the DMA, set up an interrupt, break down the playback buffer into
  66. sections that don't cross the page boundary, etc...  It's pretty 
  67. complicated, but well worth the effort.  See the included
  68. "DMAPLAY.ASM" for an example on how to do that.  See "DMAPLAY2.ASM" for 
  69. the Sound Blaster PRO stereo version.  Note that for stereo, every other
  70. byte is on a different channel.  Odd bytes are, say, on the left speaker,
  71. while even bytes play on the right.
  72.  
  73. ────────────────────────────────────────────────────────────────────────────
  74.  
  75. Here's what you must do for DMA playback:
  76.  
  77.  1) Reset DSP, Turn on speaker, set time constant (256 - 1000000/HZ)
  78.  2) Break sample into two buffers, if necessary.
  79.  3) Program the DMAC (8237) for the DMA operation.
  80.  4) Program DSP for DMA transfer.
  81.  
  82.  5) ...Up to you...
  83.  
  84.  6) When DMA is finished (interrupt occurs) you can either play another
  85.     buffer (repeat steps 3 & 4) or do nothing but acknowledge the interrupt.
  86.  7) Restore old interrupt.
  87.  8) Turn off speaker.
  88.  
  89. Your interrupt must do this:
  90.  
  91.  1) If you are to play no more, set a flag saying so and goto 3
  92.  2) Set up to play another buffer..
  93.  3) Acknowledge the interrupt
  94.  
  95. ────────────────────────────────────────────────────────────────────────────
  96.  
  97.      To play back a MOD, which is just one big sample (which your
  98. program  creates on the fly), you need to use a method which is
  99. known as "DOUBLE BUFFERING."  This should make sense.  When you
  100. create the "sample" or part of  the MOD to be played, you use up
  101. a few microseconds of processor time.  In the DMA playback, an
  102. interrupt occurs at the end of each block that is played.  If you
  103. were using one buffer, then you would have to update that buffer as
  104. soon as it was finished.  This would cause a noticeable click or
  105. pause in the playback.  Obviously, this is not exactly what one
  106. desires.  If you were using two buffers, the interrupt would, as
  107. soon as the previous buffer is played, start playing  the other
  108. buffer.  And then it can take it's sweet old time updating the
  109. first buffer.  This cycle would repeat indefinatly, or until the
  110. MOD is stopped.  A simple concept, but not all that simple to do.
  111.  
  112.      Anyway, so you have your two buffers.  You can play the two
  113. buffers  continuously.  So now all that's left is to actually
  114. create the sample to play.  Before I explain how you would go
  115. about this, we need to review some physics of sound.  First thing
  116. you must know is that when two sounds are played at the same time
  117. they add together.  So if you were to play two samples at the
  118. same  time you would simply add the individual bytes together and
  119. that would be the sample that you play.  For instance, lets
  120. suppose that we wanted to mix the  following two "samples" 
  121.  
  122. Sample1:   0  0  23  45 67 78 77 55 44 33 22 11  0
  123. Sample2:  10 88   4  91  4  3 17 21 23 10 12 40 80
  124. RESULT:   10 88  27 136 71 81 94 76 67 43 34 51 80
  125.  
  126.      You would then play the RESULT sample and it would sound
  127. like the two samples were played at the same time.  See
  128. "MIXPLAY.ASM" which takes two samples and mixes them and then
  129. plays the result via POLLING.  Unfortunately, digital sound is
  130. limited.  The sound blaster is only 8 bit.  What would happen if you
  131. mixed two samples that had the values 128+130 = 258 (= 3 in 8 bits)?  
  132. That result would cause a crackle in the sound and would generally
  133. make the playback sound like crap.  Again, that is not desirable. 
  134. Suppose now that you mixed FOUR samples together (ie four traks of a MOD.) 
  135. The maximum value that each sample could have is 64 (64*4=256),
  136. because you cannot allow the possibility of it exceeding the 8 bit
  137. range.  (In SAM format, this would translate to a +-32 range for each
  138. sample.)  Conveniently, 64 is the maximum volume for each sample in a MOD.
  139. Even so, don't forget that the range of the sample data is -128 to 127.
  140.  
  141.      Volume in sound, is simply the magnitude of the sound wave. 
  142. The bigger the range, the more air is displaced, the louder it can
  143. get.  (Or something like that...)  Since the maximum volume of a sample
  144. is 64, you can derive this formula for mixing the samples together:
  145.  
  146. result = (S1*V1 + S2*V2 + S3*V3 + S4*V4)/256
  147.  
  148.      The /256 is because we want the result to have a range of +-128
  149. and each individual sample has a max of +-128 and the volume multiplied
  150. and added for 4 traks give a maximum value of 4*64*(+-128) = 256*(+-128)... 
  151. I think you can figure that one out on your own.  This is VERY 
  152. convenient in assembler, because all you have to do for each 
  153. byte in the sample is this:
  154.  
  155. ────────────────────────────────────────────────────────────────
  156.      mov  al,[es:di]      ;es:di points to sample data
  157.      imul [Volume]        ;volume * sample data
  158.      add  [ds:si],ah      ;add the upper 8 bits
  159.                           ;ds:si point to the RESULT buffer
  160. ────────────────────────────────────────────────────────────────
  161.  
  162.      Pretty simple, eh?  That's all there is to the mixing part. 
  163. Now you  might wonder how to get the different frequencies. 
  164. This, again, is pretty  simple.  To lower the frequency you would
  165. do just that- lower the frequency (stretch it out).  This is done 
  166. by increasing the "sample source" pointer by a value less than one. 
  167. For instance, if you were to step through this "sample" with a
  168. step of 1/2, you would get the following result:
  169.  
  170. Sample: 1 2 3 4 5 6 7 8 9 0
  171. RESULT: 1 1 2 2 3 3 4 4 5 5 6 6 ...etc...
  172.  
  173.      This stretches out the sample, therefore lowering the
  174. frequency.  Similarly, to raise the frequency, you would use a
  175. step that is greater than one. In example, using the same sample
  176. above, but with a step of 2, you'd get:
  177.  
  178. RESULT: 1 3 5 7 9
  179.  
  180.      To effectively do this stepping stuff, you need "floating
  181. point" numbers.  The easiest way to do floating point numbers
  182. with integers is using what I call the integer part and the
  183. "precision."  For instance, the value of 1 and 1/2 would have as
  184. the integer value a "1" and (10000h / 2) for the precision.  This
  185. is very convenient on the 386, because you can take advantage of
  186. the 32 bit numbers.  For instance, to increase the pointer DI by
  187. an amount stored in EBP (Low BP=precision HIGH= integer) you'd
  188. simply do this:
  189.  
  190. ────────────────────────────────────────────────────────────     
  191.      ROR EDI,16    ;restore to a proper 32 bit number
  192.      ADD EDI,EBP   ;add the step
  193.      ROR EDI,16    ;put the low high and the high low..
  194. ────────────────────────────────────────────────────────────
  195.  
  196.      In this example, DI is a pointer like usual, but in the
  197. upper 16 bits, the precision is held.  EBP is just a normal 32 bit
  198. number with "1"=10000h. You may at first think,"why not just
  199. store EBP backwards, like EDI."  But clearly this would not work,
  200. because when the precision overflows, the Integer part would not
  201. be increased.  You would have a pointer that would never move or
  202. increase by an integer amount (if EBP > 0FFFFh)
  203.  
  204. ────────────────────────────────────────────────────────────
  205. -More examples of integers representing floating pt numbers-
  206.            
  207.             High  Low
  208.     
  209.     0.125=       2000h
  210.     0.25 =       4000h
  211.     0.5  =       8000h
  212.     1.0  =     1 0000h
  213.     1.5  =     1 8000h
  214.     2.0  =     2 0000h
  215.                ^  ^
  216.                |  Precision part
  217.               Integer part 
  218.  
  219.     Add:      
  220.               1.5 + 0.25  = 1.75
  221.            18000h + 4000h = 1c000h
  222.  
  223.     Multiply:
  224.               1.5 * 2.0    = 3.0
  225.            18000h * 20000h = 300000000h/10000h = 30000h
  226.       (Don't forget to divide by '1' after multiplying)
  227.  
  228.     Divide:
  229.               4.0 / 3.0    = 1.333...
  230.     40000h*10000h / 30000h = 15555h
  231.       (Don't forget to multiply by '1' before division)
  232.  
  233. ────────────────────────────────────────────────────────────
  234.  
  235.      Now, the tough part.  How do you find the step value?  Well,
  236. the step is based on two things-
  237.  
  238.  1) the note being played and
  239.  2) the sampling rate
  240.  
  241.      How you go about calculating the step is like this: you
  242. take a value proportional to the sampling rate and divide it by
  243. the NOTE frequency.  There is probably some really simple
  244. mathematical equation for figuring out precisely what the value
  245. should be, BUT I haven't spent time to figure it out.  All you
  246. know is that it is linearly proportional to the sampling rate, so
  247. you just have to play with different count values until you get
  248. one that sounds right, and then you can  figure out a relationship
  249. from there.  Here are some values for the count that  have worked
  250. for me:
  251.  
  252. ────────────────────────────────────────
  253.   COUNTTBL DD 1C78000H      ;8000  HZ
  254.       DD      16C8000H      ;10000 HZ
  255.       DD      12FC000H      ;12000 HZ
  256.       DD      1045B00H      ;14000 HZ
  257.       DD      0E3D000H      ;16000 HZ
  258.       DD      0CA8000H      ;18000 HZ
  259.       DD      0A5AE00H      ;22000 HZ
  260.  
  261.   Just in case you are wondering how the step calculation would look in 
  262. assembler...
  263.  
  264. MACRO @FigureStep     ;in: ebp = Note   out: ebp = step
  265.     push    edx
  266.     mov     eax,[Count]
  267.     xor     edx,edx
  268.     div     ebp
  269.     mov     ebp,eax
  270.     pop     edx
  271. ENDM  @FigureStep
  272.  
  273. ────────────────────────────────────────
  274.  
  275.      That information in itself is nearly enough for you to write
  276. your own MOD player.  Now I'll talk about how to read and process
  277. the notes.  First off, a brief reminder about how each note is set up:  
  278. (This is all in hex for convenience.  My convenience.)
  279.  
  280. BYTE#       1  2   3  4
  281.          ┌───┬──┬───┬──┐
  282.          │0 0│00│0 0│00│
  283.          │S NOTE│S C│XY│
  284.          │H  │  │L  │  │
  285.          └───┴──┴───┴──┘
  286.  
  287. ■ SH and SL are the high and low parts of the Sample number. 
  288. Currently, in the MOD format, only the lowest bit of the High
  289. sample is used. 5 bits = 31 possible samples (0= NULL sample, so
  290. the real range is 1-31).  
  291.  
  292. ■ NOTE is the 12 bit note frequency.  If you hit a freq = 0,
  293.   DON'T RECORD THAT FREQUENCY. (Nobody likes to divide by zero...)
  294. ■ C is the special command.
  295. ■ X & Y are the arguments for the command.
  296.   The special commands are recorded even if they are all 0's
  297.  
  298. Suppose now that [fs:si] pointed to the current note, you'd grab
  299. everything like this:
  300.  
  301. ────────────────────────────────────────────────────────────────────────────
  302.  
  303.      mov ah,[fs:si]
  304.      and ah,4
  305.      mov al,[fs:si + 1]
  306.      mov [Frequency],ax   ;get the frequency
  307.  
  308.      mov al,[fs:si]
  309.      shr al,4
  310.      and al,1             ;we only want one bit
  311.      mov ah,[fs:si + 2]
  312.      shr ah,4
  313.      or  ah,al            ;combine low & high
  314.      mov [Sample],ah      ;store the sample number
  315.  
  316.      mov al,[fs:si + 2]
  317.      and al,00001111b     ;grab the command
  318.      mov [Command],al
  319.      mov ah,[fs:si + 3]
  320.      mov [CommandXY],ah
  321.      mov al,ah
  322.      and al,00001111b     ;isolate the Y part
  323.      shr ah,4             ;isolate the X part
  324.      mov [CommandX],ah
  325.      mov [CommandY],al
  326.  
  327. ────────────────────────────────────────────────────────────────────────────
  328.  
  329.      I stored the command arguments both separately and together
  330. because some commands need to access them as a whole, some want
  331. them separate.  This was pseudo code.  While it WOULD work, this
  332. is NOT the way to do it.  The best way is to have 4 records that
  333. have all the fields you need for each trak in them.  For example,
  334. here's most of the record that I used in my newer MOD player:
  335.  
  336. ────────────────────────────────────────────────────────────────────────────
  337.  
  338. STRUC Trak
  339.  
  340.     Enabled     db  0       ;0= trak is not valid: other= play it
  341.     Delayed     db  0       ;0= not delayed, 1= sample is delayed
  342.     SpecialOn   db  0       ;0= no special, other yes
  343.  
  344.     sSeg        dw  ?       ;sample segment
  345.     sOff        dw  ?       ;sample offset
  346.     sLoopS      dw  ?       ; sample loop start
  347.     sLoopLen    dw  ?       ;lenght of loop
  348.     sEnd        dw  ?       ;ending offset of sample
  349.     sFreq       dd  ?       ;sample frequency (step)
  350.     sTFreq      dw  ?       ;temporary step value
  351.     sVolume     db  ?       ;volume
  352.     sInst       db  ?       ;the inst currently playing
  353.                 
  354.     Note        dw  ?       ;the frequency, not the step value
  355.     LastNote    dw  ?       ;the last real note played..
  356.     cmd         db  ?       ;command (0-15)
  357.     cmdX        db  ?       ;upper 4 bits of the XY
  358.     cmdY        db  ?       ;lower 4 bits..
  359.     cmdXY       db  ?       ;all 8 put together (XY)
  360.     FineTune    db  ?       ;amount shifted up or down..
  361.     Start       dw  ?       ;offset of beginning of sample (for retrigger)
  362.     
  363.     ArpeggStep  db  ?       ;either 0,1, or 2
  364.     WantedNote  dw  ?       ;used to slide to a specific note
  365.     VibratoCmd  db  ?       ;speed & Depth for Vibrato
  366.     VibratoPos  db  ?       ;position in wave chart
  367.     VibNote     dw  ?       ;base note for vib
  368.     TremoloCmd  db  ?       ;speed & depth for Tremolo   
  369.     TremoloPos  db  ?       ;position in wave chart
  370.     TremVol     db  ?       ;base volume
  371.     
  372.     ...           ;feel free to add more stuff as you need 'it!
  373.  
  374. ENDS  TRAK
  375.  
  376. TheTraks    Trak   4 dup (<>) ;declare variables for the traks
  377.  
  378. ────────────────────────────────────────────────────────────────────────────
  379.  
  380.      The easiest way to process the commands would be to use a
  381. "jump table." A jump table is simply a list of offsets to various
  382. places in your program.  It is a much faster than doing:
  383.  
  384. ────────────────────────────────────────────     
  385.      cmp    [Cmd],0   ;is it arpeggiation?
  386.      je     DoArpeg
  387.      cmp    [Cmd],1   ;is it freq slide?
  388.      je     SlideFup
  389.      ...
  390.      ...     ;etc.
  391. ────────────────────────────────────────────
  392.  
  393. A jump table would look like this:
  394.  
  395. ────────────────────────────────────────────────────────────────
  396. InitTable dw offset InitArpeg, offset InitSlideUp, offset InitSlideDn         
  397.           dw offset ...  etc.. for all 16 commands..
  398. ────────────────────────────────────────────────────────────────
  399.  
  400. You would use the jump table like this:
  401.      
  402. ────────────────────────────────────────────────────────────────────────────
  403.  
  404. PROC InitCommands 
  405.      pusha
  406.      movzx  si,[cs:Cmd]
  407.      add    si,si                     ;multiply by 2 (for word sized data)
  408.      jmp    [word cs:si + InitTable]
  409. ReturnFromInit:
  410.      popa
  411.      ret
  412. ENDP InitCommands
  413.  
  414. ────────────────────────────────────────────────────────────────────────────
  415.  
  416.      Of course, all of your little subroutines would have to, at
  417. the end of  them, return to the label ReturnFromInit by jumping
  418. to that location.  If you are wondering why I Put INIT infront of
  419. all the labels, then you are in luck  because I am going to tell
  420. you.  Most of the Commands require some code to initialize them,
  421. and then some of them require to be updated with each "tick" of
  422. the timer.  So you'd also have to do a jump chart for Update commands.
  423. Also note that you'll need two more jump charts for the Extended
  424. commands... A total of four jump charts.
  425.  
  426.      Song Speed: the timer "ticks" 50 times a second.  The song
  427. speed is  simply the number of ticks before a new note is
  428. processed.  The commands need to be updated with every tick.  The
  429. actual timing of the song can be achieved by the size of the
  430. buffer.  For convenience, I chose the buffer size to be equal to
  431. the duration of one note. For example, suppose I had a sampling
  432. rate of 22,000 hz.  That means that 22,000 bytes are played every
  433. second.  So, to  find the number of bytes in 1/50 of a second,
  434. you just divide the HZ by 50. This gives you the number of bytes
  435. in a tick.  The buffer size would then be equal to: 
  436.  
  437.         BufferSize = BytesPerTick * Songspeed.  
  438.                    = 22000/50 * 6 (default speed is 6)
  439.                    = 2640
  440.  
  441. Very simple.  But you have to allow the buffer to
  442. grow bigger (say a max of 31 ticks) this would mean that the
  443. MaxBufferSIze would be (if your max sampling rate was 22000):    
  444.  
  445.      22000/50 * 31( or 1Fh) = 13640 bytes
  446.      
  447.      This, of course means that 27280 bytes (=2*13640, 2 buffers)
  448. need to be set aside in memory (dynamically allocated, right?)
  449. for the playback buffers.
  450.  
  451.      More on song speed: speed values 20h-FFh are what's known
  452. as BPM speeds (Beats Per Minute.)  Very annoying, but they are 
  453. incredibly easy to implement (not as easy as a simple speed change,
  454. though).  What you'll end up doing is resizing the playback buffer,
  455. which may mean that the BufferSize != BytesPerTick * SongSpeed.
  456.  
  457.      The new songspeed will be equal to: 750/BPM.  The 750 came from 
  458. there being 50 ticks per second * 60 seconds per minute = 3000 ticks/min.
  459. Each 'note' is regarded as a quarter note, so 3000/4= 750.  So, in summary:
  460.  
  461. ────────────────────────────────────────────────────────────────────────────
  462.  
  463. SongSpeed = 750/BPM             ;will give you the integer speed approx
  464. Buffersize= 750 * BytesPerTick / BPM
  465.  
  466. NOTE: The Buffersize MAY be bigger than BytesPerTick*SongSpeed, so you must
  467.     use the size of the buffer to indicate the end of the note, NOT a count
  468.     of how many ticks were done.
  469.  
  470.  Some BPM's of some songspeeds:
  471. SPEED   BPM     The BPM is calculated by BPM = 750 / Speed
  472.  
  473.   4     187
  474.   5     150
  475.   6     125
  476.   7     107
  477.   8      93
  478.   9      83
  479.  10      75
  480.  11      68
  481.  
  482. ════════════════════════════════════════════════════════════════════════════
  483.  
  484. Ok, here's the actual .MOD format...
  485.  
  486.     POS = Position in file (in hex)
  487.     LEN = Length in bytes (in hex)
  488.     Description = The jello to mass ratio of a frog (in hex)
  489.  
  490. POS     LEN     DESCRIPTION
  491.  
  492. 0000    0014    Mod name. Should be a ASCIIZ string, but you never know.
  493. 0014    03A2    Sample data (see the below structure "SampleStruc")
  494. 03B6    0001    Number of Valid sequences.
  495. 03B7    0001    Says if the mod is to be restarted. Ignore it. Not reliable.
  496. 03B8    0080    The sequences. All 128 of 'em.
  497. 0438    0004    The initials "M.K."  You could, if you really wanted to, 
  498.                 verify that the file is a MOD by looking at this signature.
  499.  
  500. 043C    0400    The patterns. Each is 1024 bytes long, but you have to figure
  501.                 out how many there are by finding the MAXIMUM of all the
  502.                 pattern #'s in the sequence list. Then you add 1. (0 is a
  503.                 valid pattern.)
  504.  
  505. ????    ????    Immediately after the last pattern, the samples begin.
  506.                 You have to read them in in order.  The size is in the 
  507.                 header.
  508.  
  509. ------- -------
  510.  
  511.         Here's the structure you'd use for each sample:
  512.  
  513. STRUC SampleStruc
  514.   Name        db  22 dup (?)
  515.   Length      dw  ?
  516.   FineTune    db  ?
  517.   Volume      db  ?
  518.   LoopStart   dw  ?
  519.   LoopLength  dw  ?
  520. ENDS  SampleStruc
  521.  
  522. NOTE:   The Lenght, LoopStart, LoopLength are, by IBM standards, screwed up.
  523.         They are stored in the AMIGA format (BIG surprise...) which means
  524.         that instead of the LOW byte being first in memory, the HIGH byte is
  525.         first.  You need to switch them.  Those values are also a measure of
  526.         how many WORDS long the sample is. (Multiply by 2 to get # of bytes.)
  527.  
  528. FINETUNE:
  529.         The fine tune is only a signed NIBBLE! You fix it into a signed byte
  530.         by doing this:
  531.  
  532.         SHL     [Sample.Finetune], 4
  533.         SAR     [Sample.Finetune], 4
  534.  
  535.     The AMIGA Guru's say that finetuning is done by multiplying the frequency
  536. (the note) by X^(-finetune) where X = 1.0072382087. I  say, shaw, right!  
  537. Like I'm going to do that!  I say do this:
  538.  
  539.     note= note - note*2*finetune/256    ;this is pretty accurate
  540.  
  541. OR, if you are REALLY lazy, do this:
  542.  
  543.     note= note - 6*finetune     ;this ONLY works for the lower tones
  544.                                 ; but who cares!?  It's close enough to 
  545.                                 ; fool most people...
  546.  
  547.     This finetune adjustment must be made each time a note is changed.
  548.  
  549. VOLUME: This value SHOULD be between 0 and 64. Make sure it is.
  550.  
  551. ────────────────────────────────────────────────────────────────────────────
  552.  
  553.     So, the easiest way to load in the header is to create a header and
  554. load in the first 043Ch bytes right into it.  Then you can do your stuff!
  555.  
  556. MODHEADER:
  557.         SongName    db        20 dup (0)
  558.         Samples   SampleSTRUC 31 dup(<>)
  559.         NumSequence db        0
  560.         Restart     db        0
  561.         Sequences   db        128 dup (0)
  562.         TheMKSig    db        "M.K."       ;the "M.K." signature
  563.         
  564. ────────────────────────────────────────────────────────────────────────────
  565.                            FORMAT OF THE PATTERNS
  566.  
  567.     The patterns are just 64 "events".  Each "event" is made up of four
  568. notes.  These four notes are made up of 4 bytes. 64*4*4=1024 bytes total.
  569.  
  570. Format of a NOTE:  This appeared a ways back, but heck, do you want to look
  571. ALL the way up there again?
  572.  
  573. BYTE#       1  2   3  4
  574.          ┌───┬──┬───┬──┐
  575.          │0 0│00│0 0│00│
  576.          │S NOTE│S C│XY│
  577.          │H  │  │L  │  │
  578.          └───┴──┴───┴──┘
  579.  
  580. ■ SH and SL are the high and low parts of the Sample number. 
  581. Currently, in the MOD format, only the lowest bit of the High
  582. sample is used. 5 bits = 31 possible samples (0= NULL sample, so
  583. the real range is 1-31).  
  584.  
  585. ■ NOTE is the 12 bit note frequency.  If you hit a freq = 0,
  586.   DON'T RECORD THAT FREQUENCY. (Nobody likes to divide by zero...)
  587. ■ C is the special command.
  588. ■ X & Y are the arguments for the command.
  589.  
  590.     You'd index the correct "event" (I don't know what it's called..)
  591. by doing something like this:
  592.  
  593. ────────────────────────────────────────────────────────────────────────────
  594.     mov     si,[CurPattern]
  595.     shl     si,10           ;multiply by 1024
  596.     mov     ax,[CurNote]
  597.     shl     ax,4            ;multiply by 16
  598.     add     si,ax           ;si points to the correct set of notes.
  599. ────────────────────────────────────────────────────────────────────────────
  600.  
  601. Here's the list of protracker commands... As you might guess by the credits
  602. below, I did not write this...
  603.  
  604. ════════════════════════════════════════════════════════════════════════════
  605.  
  606. Protracker V2.3A/3.01 Effect Commands
  607. ----------------------------------------------------------------------------
  608. 0 - Normal play or Arpeggio             0xy : x-first halfnote add, y-second
  609. 1 - Slide Up                            1xx : upspeed
  610. 2 - Slide Down                          2xx : downspeed
  611. 3 - Tone Portamento                     3xx : up/down speed
  612. 4 - Vibrato                             4xy : x-speed,   y-depth
  613. 5 - Tone Portamento + Volume Slide      5xy : x-upspeed, y-downspeed
  614. 6 - Vibrato + Volume Slide              6xy : x-upspeed, y-downspeed
  615. 7 - Tremolo                             7xy : x-speed,   y-depth
  616. 8 - NOT USED
  617. 9 - Set SampleOffset                    9xx : offset (23h -> 2300h)
  618. A - VolumeSlide                         Axy : x-upspeed, y-downspeed
  619. B - Position Jump                       Bxx : songposition
  620. C - Set Volume                          Cxx : volume, 00-40
  621. D - Pattern Break                       Dxx : break position in next patt
  622. E - E-Commands                          Exy : see below...
  623. F - Set Speed                           Fxx : speed (00-1F) / tempo (20-FF)
  624. ----------------------------------------------------------------------------
  625. E0- Set Filter                          E0x : 0-filter on, 1-filter off
  626. E1- FineSlide Up                        E1x : value
  627. E2- FineSlide Down                      E2x : value
  628. E3- Glissando Control                   E3x : 0-off, 1-on (use with tonep.)
  629. E4- Set Vibrato Waveform                E4x : 0-sine, 1-ramp down, 2-square
  630. E5- Set Loop                            E5x : set loop point
  631. E6- Jump to Loop                        E6x : jump to loop, play x times
  632. E7- Set Tremolo Waveform                E7x : 0-sine, 1-ramp down. 2-square
  633. E8- NOT USED
  634. E9- Retrig Note                         E9x : retrig from note + x vblanks
  635. EA- Fine VolumeSlide Up                 EAx : add x to volume
  636. EB- Fine VolumeSlide Down               EBx : subtract x from volume
  637. EC- NoteCut                             ECx : cut from note + x vblanks
  638. ED- NoteDelay                           EDx : delay note x vblanks
  639. EE- PatternDelay                        EEx : delay pattern x notes
  640. EF- Invert Loop                         EFx : speed
  641. ----------------------------------------------------------------------------
  642. Peter "CRAYON" Hanning /Mushroom Studios/Noxious
  643.  
  644. ════════════════════════════════════════════════════════════════════════════
  645.  
  646.     Now into the implementation of all those little commands...
  647.  
  648. ARPEGGIO:
  649.     You just step between 3 notes: note, note + x, note + y
  650.     Don't forget to recalculate the step value after changing the note.
  651.  
  652. SLIDES:
  653.     For up, the value XY is subtracted from the NOTE on each tick.
  654.     Down, you add.. Keep the values within the range 83-832.
  655.  
  656. SLIDE TO NOTE:
  657.     The note that is currently in the NOTE field is what you are sliding to.
  658.     You must keep a backup of the last note so that you know where you are
  659.     sliding from.  Add or subtract XY on each tick so that you move closer
  660.     to the note.
  661.     - If the NOTE field = 0, you are supposed to continue sliding to the
  662.       last note specified
  663.     - I think that if the XY field = 0, that you are just supposed to
  664.       continue whatever slide was last active at the last speed specified.
  665.  
  666. VIBRATO:
  667.     For this, you need a chart of a sine wave, square wave, and something
  668.     called "ramp down."  The maximum value in this chart should be 255, the 
  669.     minimum -255.  One half period in the sine wave should be 32 entries.
  670.     That would mean you have a total of 64 entries, half negative, half not.
  671.     On each tick you increase the index into the chart by X (the speed).
  672.     You grab the value there and multiply Y (the depth) by that value and
  673.     divide by 256.  You then add that value to the BaseNote and recalculate
  674.     the Step.
  675.         Note that you must, upon initializing, grab all the info you need,
  676.     (note & XY) because this continues until a new note is put in.  It also 
  677.     has to work with volume slides.
  678.     - If the XY field = 0, you are supposed to continue whatever vibrato
  679.       was last active.  I'm also pretty sure that you are not supposed to 
  680.       reset the index every time a vibrato is called.
  681.  
  682.  
  683. NOTE SLIDE + VOLUME SLIDE:
  684.     For the INIT, you just call the InitVolume subroutine (this is the only
  685.     on that needs it's own subroutine, other than glissando.)
  686.     To update, you call the UpdateVolume subroutine and then jump to the
  687.     Slide to NOTE routine.
  688.  
  689. VIBR + VOLUME SLIDE:
  690.     Same as above.
  691.  
  692. TREMOLO:
  693.     Same as Vibrato, but instead of changing the NOTE, you change the volume.
  694.     You can use the same charts.
  695.  
  696. VOLUME SLIDE:
  697.     Upon initializing, you want to see if its an up slide or a down slide and
  698.     then extend that nibble out to a signed byte (ie. 04 => -4, 40 => 4.)
  699.     On each tick, you add that value to the volume.  Be sure to keep the 
  700.     volume within the range 0-64.
  701.  
  702. POSITION JUMP:
  703.     Remember that you are jumping to a sequence and not a pattern.  Otherwise
  704.     this is darn simple.
  705.  
  706. SET VOLUME:
  707.     Gee, I don't know...
  708.  
  709. PATTERN BREAK:
  710.     Set the current note to 64, so that on the next update, it wraps around
  711.     to the next sequence.
  712.  
  713. SET SPEED:
  714.     You must calculate both the SONGSPEED and the BUFFERSIZE.
  715.     If the XY <= 1Fh then that's easy, you just use that value as the song
  716.     speed and use BUFFERSIZE = SongSpeed * BytesPerTick.
  717.  
  718.     For BPM, do it the way I suggested a couple pages ago...
  719.  
  720.             EXTENDED COMMANDS:
  721.  
  722. SET FILTER:
  723.     Yeah, right.  As if the SB had a filter!
  724.  
  725. FineSlide Up/Down:
  726.     Add/subtract the x value to/from the NOTE. Recalculate the step.
  727.     This is done ONCE upon initialization.  No update routine is needed.
  728.  
  729. Glissando:
  730.     This is really a luxury.  You don't have to implement it. 
  731.     But, if you want to, you do it like this...
  732.  
  733.     1) Create a chart of all the possible WHOLE notes (exclude sharps, flats,
  734.         etc...)
  735.     2) Slide the NOTE up or down like normal, but if Glissando is on, you
  736.         have to look up your adjusted note in the chart and round to the
  737.         nearest one.  I suggest that you don't save this rounded off note, 
  738.         but just use it to calculate the step.
  739.  
  740. Set Vibrato Waveform:
  741.     Currently, there are 3 possibilities, sine, ramp down, and square wave.
  742.     You might want to implement this by making the Vibrato reference the 
  743.     chart indirectly.  That way you just load in the offset to the chart
  744.     into the VibratoChart variable.  And that's it.
  745.  
  746.     example:
  747.         ...
  748.         mov     si,[VibIndex]       ;grab the index
  749.         add     si,si               ;multiply by 2 (word sized data)
  750.         mov     bx,[VibratoChart]   ;get the offset to the current chart
  751.         mov     ax,[si+bx]          ;grab the value
  752.         ...
  753.  
  754. Set Loop:
  755.     You just have to store the current position in the pattern.
  756.  
  757. Jump to Loop and play:
  758.     This is one that you'll just have to figure out yourself...
  759.     It's probably the toughest one to implement... :)
  760.     The second part of Set Loop.
  761.  
  762. Set Tremolo Waveform:
  763.     Same as for Vibrato.
  764.  
  765. Retrigger Note:
  766.     When the current Tick = x then reload the start offset into the current 
  767.     source pointer.  That means that you must keep track of what current
  768.     tick you are on.
  769.  
  770. Fine Vol slide up:
  771.     Add this value to the volume on initialization. No update.
  772.  
  773. Fine Vol slide down:
  774.     Subtract this value from the volume on initialization. No update.
  775.  
  776. NoteCut:
  777.     At tick x, terminate the sample. (set ending offset = 0 or something)
  778.  
  779. NoteDelay:
  780.     Set the delay flag on init.  Your mixer routine should have an extra
  781.     loop that will wait until the delay flag is off (and call UpdatePro)
  782.     Turn off the flag when Tick = x
  783.  
  784. PatternDelay:
  785.     Just another one of those thing.  Put the delay flag in front of your
  786.     "grab the note" routine.  Don't grab any notes until the delay is zero.
  787.  
  788.     Example:
  789.  
  790.     PROC ReadAllTheNotes NEAR
  791.         cmp     [PatternDelay],0
  792.         je      ReadTheNotes
  793.         dec     [PatternDelay]
  794.         ret
  795.     ReadTheNotes:
  796.         ... 
  797.         
  798. Invert Loop:
  799.     To be honest, I haven't a clue.  I've never seen a MOD that uses it.
  800.  
  801. ────────────────────────────────────────────────────────────────────────────
  802.     OK, for those who still aren't exactly sure how to do this update thing,
  803. I've included the routine that I use to actually mix the data.  The buffer
  804. was already cleared to 128's.  Note that this routine is called 4 times, 
  805. once for each trak.  The segments were pushed in the main routine.
  806.  
  807. ════════════════════════════════════════════════════════════════════════════
  808.  
  809.     ;IN: BX = (Trak to update) * (size TRAK)
  810. PROC    UpdateTrak  ;called to update the traks
  811.     pushad
  812.     mov     ax,cs
  813.     mov     ds,ax
  814.     mov     ax,[BufferSeg]
  815.     mov     es,ax
  816.  
  817.     mov     ax,[BytesPerTick]
  818.     inc     ax
  819.     mov     [BPTCounter],ax
  820.     mov     ax,[SongSpeed]
  821.     mov     [TickCounter],ax
  822.     mov     [CurTick],0
  823.  
  824.     mov     si,[CurOff]             ;es:si is pointer to buffer
  825.     mov     cx,[CurBuffSize]        ;TmpCurBuffSize is the length
  826.     inc     cx
  827.     mov     [TmpCurBuffSize],cx
  828.  
  829.     mov     fs,[bx + TheTraks.sseg] ;fs:di is pointer to Sample data
  830.     xor     edi,edi
  831.     mov     di,[bx + TheTraks.soff]
  832.     mov     cx,[bx + TheTraks.send] ;cx is ending offset of sample
  833.     mov     ebp,[bx+ TheTraks.sfreq]    ;step for note
  834.     mov     dl,[bx + TheTraks.svol] ;dl is volume
  835.  
  836. @@DelayedLoop:
  837.     cmp     [bx + TheTraks.sdelayed],0
  838.     je      @@TheLoop           ;check if we are delaying this trak...
  839.     mov     ax,[BPTCounter]
  840.     add     si,ax
  841.     sub     [TmpCurBuffSize],ax
  842.     jbe     @@EndOfUpdate
  843.  
  844.     call    ProTrackerUpdate
  845.  
  846.     inc     [CurTick]
  847.     jmp     @@DelayedLoop
  848.     
  849. @@TheLoop:
  850.     mov     al,[fs:di]
  851.     imul    dl
  852.     add     [es:si],ah      ;do one byte of the sample
  853.     
  854.     ror     edi,16          ;increase the pointer
  855.     add     edi,ebp
  856.     rol     edi,16
  857.     cmp     di,cx
  858.     ja      @@HandleEndOfSample
  859.  
  860. @@BackFromEOS:
  861.     inc     si
  862.     dec     [TmpCurBuffSize]
  863.     je      @@EndOfUpdate
  864.     dec     [BPTCounter]
  865.     jne     @@TheLoop
  866.  
  867.     call    ProTrackerUpdate
  868.  
  869.     mov     ax,[BytesPerTick]
  870.     inc     ax
  871.     mov     [BPTCounter],ax
  872.     inc     [CurTick]
  873.     jmp     @@TheLoop
  874.  
  875. @@EndOfUpdate:
  876.     mov     [bx + TheTraks.soff],di
  877.     mov     [bx + TheTraks.send],cx     ;cx is ending offset of sample
  878.     mov     [bx +TheTraks.sfreq],ebp    ;step for note
  879.     mov     [bx + TheTraks.svol],dl     ;dl is volume
  880.  
  881.     popad
  882.     ret
  883.     
  884. @@HandleEndOfSample:
  885.     cmp     [bx + TheTraks.slooplen],0
  886.     jne     @@DoARepeat
  887.     mov     [bx + TheTraks.sEnabled],0  ;disable the track
  888.     jmp     @@EndOfUpdate
  889. @@DoARepeat:
  890.     mov     di,[bx + TheTraks.sloops]   ;start of loop
  891.     add     di,[bx + TheTraks.Start]
  892.     mov     cx,[bx + TheTraks.slooplen]
  893.     add     cx,di                       ;set up ending address
  894.     jmp     @@BackFromEOS
  895.  
  896. ENDP    UpdateTrak
  897.  
  898. ════════════════════════════════════════════════════════════════════════════
  899.  
  900.     Ok, all that's really left is the writing of a load subroutine and of 
  901. the routine that reads and processes the notes.  And, of course, you need to
  902. implement all of those cute little ProTracker routines.  And, well, you need
  903. to fix up the DMA driver...  Geeze, there sure is a lot to a MOD player, 
  904. isn't there?  Probably why not everyone has written one. :)
  905.  
  906. ────────────────────────────────────────────────────────────────────────────
  907.  
  908.     Well, that's about all...  This info is enough to get ANY competent
  909. programmer started making a MOD player...  I hope you enjoyed this little
  910. info file.
  911.  
  912.    ■ Draeden - VLA - Main Coder
  913.  
  914. ┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐
  915. └┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘
  916.  
  917.        You are free to use all code in the associated files ( DMAPLAY.ASM,
  918.     DMAPLAY2.ASM, POLLPLAY.ASM, MIXPLAY.ASM, DACPLAY.ASM, MODINFO.DOC ) on
  919.     the condition that you greet VLA in your future releases.  A kind word
  920.     about how you appreciate files like this wouldn't hurt either. :)
  921.  
  922.                 See VLA.NFO for information on contacting us.
  923.  
  924. ┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐
  925. └┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘
  926.